package elEMAS.impl;

import java.util.List;

import common.GeneticHelper;
import common.GeneticOperations;

import elEMAS.inf.Agent;
import elEMAS.inf.Island;

public class ElEmasAlgorithm<Genotype> extends EmasAlgorithm<Genotype> {
	
	public static int stat_numOfAgentsThatBecameElitist = 0;
	public static int stat_numOfNeighboursMeetings = 0;
	public static int stat_numOfNonNeighboursMeetings = 0;

	private double calc_elitistHVR;
	private double calc_elitistHV;
	private ElEmasParameters elParams;

    private EmasElitistIsland<Genotype> elitistIsland;

    public ElEmasAlgorithm(GeneticOperations<Genotype> aGo, ElEmasParameters aParams) {
        
        super(aGo,aParams);
        
        this.elParams = aParams;
        this.elitistIsland = new EmasElitistIsland<Genotype>();
    }
    
    public double calculateHV() {
        
        elitistIsland.addAllAgents(getAllAgents());
        return GeneticHelper.calculateHiperValume(getElitists(), params.ref_f0, params.ref_f1);
    }
    
    public void printParameters() {
        
        int p = 0;
        System.out.println("Parametry:");
        System.out.println(++p+") plik z parametrami = "+params.configFile);
        System.out.println(++p+") plik wejściowy = "+params.inputFile);
        System.out.println(++p+") ilosc krokow = "+params.stepNum);
        System.out.println(++p+") poczatkowa ilosc wszystkich agentow = "+params.agentsNum);
        System.out.println(++p+") srednio agentow na wyspie = "+(((double)params.agentsNum)/params.islandNum));
        System.out.println(++p+") ilosc wysp = "+params.islandNum);
        System.out.println(++p+") HV_ref0 = "+params.ref_f0);
        System.out.println(++p+") HV_ref1 = "+params.ref_f1);
        
        System.out.println(++p+") poczatkowa energia agenta = "+params.startAgentEnergy);
        System.out.println(++p+") prog smierci             = "+params.dieThreshold);
        System.out.println(++p+") prog reprodukcji         = "+params.reproductionThreshold);
        System.out.println(++p+") promien sasiedztwa = "+elParams.neighbourDistance);
        System.out.println(++p+") prog elitarnosci   = "+elParams.elitistPrestigeLimit);     
        System.out.println(++p+") prawdopodobienstwo migracji osonika = "+params.migrationProbability);
    }


    public void calculateParams() {
        
        super.calculateParams();
        this.calc_elitistHV = GeneticHelper.calculateHiperValume(getElitists(),params.ref_f0,params.ref_f1);
        this.calc_elitistHVR = this.calc_elitistHV / this.calc_optimalHV;
    }

    public double getHVRelitist() {
        return this.calc_elitistHVR;
    }
    
    public double getHVelitist() {
        return this.calc_elitistHV;
    }
	
    public List<Agent<Genotype>> getElitists() {
        return elitistIsland.getAgents();
    }
    
    public void printResultStatistics() {
        
        //printAndWriteAgents("write","wynikAgenty.txt",allAgents);
        
        // checking if all energy is right
        int allEnergy = 0;
        allEnergy += envEnergy;
        
        List<Agent<Genotype>> allAgents = getAllAgents();
        for (Agent<Genotype> agent : allAgents) {
            allEnergy += agent.getEnergy();
            assert agent.getEnergy() >= 0 : "energy: "+agent.getEnergy();
        }
        
        int beginEnergy = params.agentsNum * params.startAgentEnergy;
        assert allEnergy == beginEnergy : "allEnergy "+allEnergy+" != "+beginEnergy;
        
        System.out.println("Czas wszystkich obliczen: " + (endMili-begMili) / 1000);
        System.out.println("Ilosc agentow w systemie = "+allAgents.size());
        System.out.println("Calkowita energia w systemie = "+allEnergy);
        
        double generatedPrecent = ((double)stat_numOfBornAgents)/(stat_numOfBornAgents+stat_numOfAgentsCreatedByEnv)*100;
        System.out.println("Nowi agenci:");
        System.out.println("   a) utworzoni przez srodowisko = "+stat_numOfAgentsCreatedByEnv);
        System.out.println("   b) urodzeni                   = "+stat_numOfBornAgents);
        System.out.println("   c) procent urodzonych         = "+generatedPrecent+"%");
        int allCreatedOrBornAgents = stat_numOfAgentsCreatedByEnv + stat_numOfBornAgents;
        System.out.println("   d) srednia ilość urodzonych na turę = " + ((double)allCreatedOrBornAgents / stat_stepNumbers));
        
        
        System.out.println("Ilosc agentow usunietych z systemu:");
        System.out.println("   a) bo stali sie elitarni = "+stat_numOfAgentsThatBecameElitist);
        System.out.println("   b) bo umarli             = "+stat_numOfDeaths);
        
        double elitistEliminatedPercent = 100*((double)stat_numOfAgentsThatBecameElitist) /
                                               (stat_numOfAgentsThatBecameElitist+stat_numOfDeaths);
        System.out.println("   c) procent elitarnych    = "+elitistEliminatedPercent);
        System.out.println("   d) ilosc umierajacych na ture = "+(((double)stat_numOfDeaths) / stat_stepNumbers));
        System.out.println("   e) ilosc usuw. elitarnych na ture = "+(((double)stat_numOfAgentsThatBecameElitist) / stat_stepNumbers));
        
        System.out.println("Ilosc spotkanych sasiadĂłw = "+stat_numOfNeighboursMeetings);
        System.out.println("Ilosc spotkanych niesasiadow = "+stat_numOfNonNeighboursMeetings);
        double meetingRatio = (((double)stat_numOfNeighboursMeetings) / (stat_numOfNeighboursMeetings+stat_numOfNonNeighboursMeetings))*100;
        System.out.println("Procent spotkan sasiadow = "+meetingRatio);
        System.out.println("Ilosc migracji = "+stat_numOfMigrations);
        double migrationPerStep = ((double)stat_numOfMigrations) / stat_stepNumbers;
        System.out.println("Srednia ilosc migracji na krok wynosi = "+migrationPerStep);
        System.out.println("Ilość kroków = "+stat_stepNumbers);
        
        //System.out.println("Optymalna calka wynosi "+er.getOptimalHV());
        System.out.println("HVR z elitarnych ("+getElitists().size()+") wynosi: "+getHVelitist());
        System.out.println("HVR ze wszystkich ("+getAllAgents().size()+") wynosi "+getHVnormal());
    }

    @Override
    void createAgent(Island<Genotype> targetIsland) {
        Genotype genotype = go.createRandomGenotype();
        if (elitistIsland == null) throw new RuntimeException();
        new elEmasAgent<Genotype>(genotype,go,targetIsland,elitistIsland,islands,elParams);
    }
}